package JavaUtils.web;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import JavaUtils.CSUtils.CBytes;
import JavaUtils.CSUtils.Log.CLog;

import java.io.*;
import java.net.Socket;
import java.util.*;

public class CWebClientThread implements Runnable {
    static final String tag = "CWebClientThread";
    static Map<String, IWebCallback> o_eventMap = new HashMap<>();
    Socket socket;
    InputStream inputStream;
    BufferedReader buffReader;
    OutputStream ouSt;
    PrintStream prSt;
    ReqInfo reqInfo;
    long dataLen;

    public CWebClientThread(Socket s) {
        this.socket = s;
    }

    public void run() {
        reqInfo = new ReqInfo();
        try {
            inputStream = socket.getInputStream();
            buffReader = new BufferedReader(new InputStreamReader(inputStream));
            ouSt = socket.getOutputStream();
            prSt = new PrintStream(ouSt);

            String data = "";
            String handStr = "";
            int len = 0;
            byte[] bytes = new byte[1024 * 256];
            while ((len = inputStream.read(bytes)) > 0) {
                CLog.i(tag, "循环接收数据......." + len);
                if (reqInfo.requestType == null) {
                    reqInfo.handerStr = new String(bytes, 0, (Math.min(len, 4500)));
                    CLog.i(tag, "接收头......." + reqInfo.handerStr);
                    reqInfo.handEndPos = -1;
                    for (int i = 4; i < len; i++) {
                        if (bytes[i - 3] == 13 && bytes[i - 2] == 10 && bytes[i - 1] == 13 && bytes[i] == 10) {
                            reqInfo.handEndPos = i + 1;
                            break;
                        }
                    }
                    handStr += new String(bytes, 0, reqInfo.handEndPos);
                    if (reqInfo.handEndPos > 0) {
                        if (!ReqInfo.GetHanderData(handStr, reqInfo)) {
                            responseTxtFile(reqInfo);
                            return;
                        }
                        //String sss = new String(bytes, reqInfo.handEndPos, len - reqInfo.handEndPos);
                        reqInfo.dataBytesList.add(CBytes.subBytes(bytes, reqInfo.handEndPos, len - reqInfo.handEndPos));
                        dataLen = len - reqInfo.handEndPos;
                    }
                } else {
                    if (len == bytes.length) {
                        reqInfo.dataBytesList.add(bytes);
                    } else {
                        reqInfo.dataBytesList.add(CBytes.subBytes(bytes, 0, len));
                    }
                    dataLen += len;
                }
                if (len < bytes.length) {
                    break;
                }
            }

            if ("post".equals(reqInfo.requestType)) {
                reqInfo.contentLength = Long.parseLong(reqInfo.headerMap.get("Content-Length"));
                reqInfo.postDataType = reqInfo.dataMap.get("postDataType");
                reqInfo.dataStr = "";
                if (ReqInfo.cDataTypeJson.equals(reqInfo.postDataType)) {
                    for (byte[] _bytes : reqInfo.dataBytesList) {
                        reqInfo.dataStr += new String(_bytes);
                    }
                    try {
                        JSONObject obj = JSON.parseObject(reqInfo.dataStr);
                        Set<String> keysArr = obj.keySet();
                        for (String key : keysArr) {
                            String data23 = obj.getString(key);
                            reqInfo.dataMap.put(key, data23);
                        }
                        reqInfo.dataMap.put("json_data", data);
                    } catch (Exception e) {

                    }
                } else if (ReqInfo.cDataTypeFormData.equals(reqInfo.postDataType)) {
                    FormDataUtil.parse(reqInfo.dataBytesList, reqInfo.dataMap);
                } else if (ReqInfo.cDataTypeTxt.equals(reqInfo.postDataType)) {
                    for (byte[] _bytes : reqInfo.dataBytesList) {
                        reqInfo.dataStr += new String(_bytes);
                    }
                }
            } else if ("get".equals(reqInfo.requestType)) {

            }
            if (ReqInfo.cDataTypeBytes.equals(reqInfo.postDataType)) {
                _readBytes();
            } else {
                _msgHandle();
            }
        } catch (Exception e) {
            CLog.ex(tag, "致命错误..." + reqInfo.url, e);
            responseTxtFile(reqInfo);
        } finally {
            // responseTxtFile(null, null, null, null);
        }
    }

    void _readBytes() {
        try {
            CLog.i(tag, "循环接收bytes消息.......................");
            if (dataLen >= reqInfo.contentLength) {
                _msgHandle();
                return;
            }
            byte[] bytes = new byte[1024 * 1024 * 10];
            int count = 0;
            int len;
            while (true) {
                len = inputStream.read(bytes);
                count++;
                if (len < 0) {
                    response(reqInfo);
                    break;
                }
                reqInfo.dataBytesList.add(CBytes.subBytes(bytes, 0, len));
                dataLen += len;
                CLog.f(tag, "循环接收......len=%d......bytes=%d.......dataLen=%d......count=%d.......contentLength=%d", len, bytes.length, dataLen, count, reqInfo.contentLength);

                //CLog.info("循环监听消息.......接收的消息长度:............" + len);
                //byte[] buffer1 = CBytes.SubBytes(megBytes, 0, rlength);
                if (dataLen >= reqInfo.contentLength) {
                    _msgHandle();
                    break;
                }
            }
        } catch (Exception e) {
            CLog.ex(tag, "连接异常断开....." + e.getMessage());
        } finally {

        }
        CLog.e(tag, "客户端已退出：" + socket);
    }

    void _msgHandle() {
        try {
            if (o_eventMap.containsKey(reqInfo.fileName)) {
                IWebCallback callback = o_eventMap.get(reqInfo.fileName);
                try {
                    CLog.i(tag, "收到消息......." + reqInfo.toString());
                    callback.MsgHandle(reqInfo);
                    response(reqInfo);
                } catch (Exception e) {
                    CLog.ex(tag, "致命错误..." + reqInfo.url, e);
                }
            } else {
                responseTxtFile(reqInfo);
            }
        } catch (Exception e) {
            CLog.ex(tag, "致命错误..." + reqInfo.url, e);
            responseTxtFile(reqInfo);
        } finally {
            // responseTxtFile(null, null, null, null);
            this.close();
        }
    }


    void response(ReqInfo reqInfo) {
        prSt.println("HTTP/1.1 " + reqInfo.resp_state + " OK");
        prSt.println("Data:" + new Date());
        prSt.println("Server: JHServer");
        prSt.println("Access-Control-Allow-Origin:*");
        prSt.println("Content-Type: text/html; charset=UTF-8");
        prSt.println();
        if (reqInfo.resp_bytes != null) {
            try {
                prSt.write(reqInfo.resp_bytes);
            } catch (Exception ex) {
                CLog.exf(tag, "web返回二进制失败.....url=%s... .....", reqInfo.fileName);
            }
        } else {
            prSt.println(reqInfo.resp_txt);
        }
        prSt.flush();
        CLog.f(tag, "web消息结束.....url=%s... .....", reqInfo.fileName);
        prSt.close();
    }

    /**
     * @description: 读取资源文件，响应给浏览器。
     * @param:@param filePath  资源文件路径
     */
    Boolean responseTxtFile(ReqInfo reqInfo) {
        if (reqInfo.fileName != null && !reqInfo.fileName.equals("/")) {
            // 读取请求头， 如：GET /index.html HTTP/1.1
            //获得项目下的路径
            String path = System.getProperty("user.dir");
            File file = new File(path + reqInfo.fileName);
            if (file.exists()) {
                // 1、资源存在，读取资源
                try {
                    //做个判断是否为空
                    BufferedReader reader = new BufferedReader(new FileReader(file));
                    System.out.println("reader" + reader);
                    StringBuffer sb = new StringBuffer();
                    String line = null;
                    while ((line = reader.readLine()) != null) {
                        sb.append(line).append("\r\n");
                    }
                    StringBuffer result = new StringBuffer();
                    result.append("HTTP /1.1 200 ok \r\n");
                    result.append("Content-Type:text/html \r\n");
                    result.append("Content-Length:" + file.length() + "\r\n");
                    result.append("\r\n" + sb.toString());
                    //System.out.println("result=="+result);
                    prSt.write(result.toString().getBytes());
                    prSt.flush();
                    prSt.close();
                } catch (Exception e) {
                    CLog.ex(tag, "致命错误...", e);
                }

            } else {
                // 2、资源不存在，提示 file not found
                StringBuffer error = new StringBuffer();
                error.append("HTTP /1.1 400 file not found \r\n");
                error.append("Content-Type:text/html \r\n");
                error.append("Content-Length:20 \r\n").append("\r\n");
                error.append("<h1 >File Not Found..</h1>");
                try {
                    prSt.write(error.toString().getBytes());
                    prSt.flush();
                    prSt.close();
                } catch (IOException e) {
                    CLog.ex(tag, "致命错误...", e);
                }
            }
        } else {
            //默认界面
            StringBuffer error = new StringBuffer();
            error.append("HTTP /1.1 200 hello word \r\n");
            error.append("Content-Type:text/html \r\n");
            error.append("Content-Length:20 \r\n").append("\r\n");
            error.append("<h1 >hello word</h1>");
            try {
                prSt.write(error.toString().getBytes());
                prSt.flush();
                prSt.close();
            } catch (IOException e) {
                CLog.ex(tag, "致命错误...", e);
                return false;
            }
        }
        return true;
    }


    void close() {
        try {
            if (this.buffReader != null) {
                this.buffReader.close();
                this.buffReader = null;
            }
            if (this.prSt != null) {
                this.prSt.close();
                this.prSt = null;
            }
            if (this.socket != null) {
                this.socket.close();
                this.socket = null;
            }
            CLog.i(tag, "一个客户端已断开连接...");
        } catch (IOException e) {
            CLog.ex(tag, "致命错误...", e);
        }
    }

}